<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
      <title>Building Your Own Rendering Canvas | HiAPI-C# 2025 </title>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta name="title" content="Building Your Own Rendering Canvas | HiAPI-C# 2025 ">
      
      
      <link rel="icon" href="../../../../../img/HiAPI.favicon.ico">
      <link rel="stylesheet" href="../../../../../public/docfx.min.css">
      <link rel="stylesheet" href="../../../../../public/main.css">
      <meta name="docfx:navrel" content="../../../../../toc.html">
      <meta name="docfx:tocrel" content="../../../toc.html">
      
      <meta name="docfx:rel" content="../../../../../">
      
      
      
      <meta name="loc:inThisArticle" content="In this article">
      <meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
      <meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
      <meta name="loc:tocFilter" content="Filter by title">
      <meta name="loc:nextArticle" content="Next">
      <meta name="loc:prevArticle" content="Previous">
      <meta name="loc:themeLight" content="Light">
      <meta name="loc:themeDark" content="Dark">
      <meta name="loc:themeAuto" content="Auto">
      <meta name="loc:changeTheme" content="Change theme">
      <meta name="loc:copy" content="Copy">
      <meta name="loc:downloadPdf" content="Download PDF">

      <script type="module" src="./../../../../../public/docfx.min.js"></script>

      <script>
        const theme = localStorage.getItem('theme') || 'auto'
        document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
      </script>

  </head>

  <body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
    <header class="bg-body border-bottom">
      <nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
        <div class="container-xxl flex-nowrap">
          <a class="navbar-brand" href="../../../../../index.html">
            <img id="logo" class="svg" src="../../../../../img/HiAPI.logo.png" alt="">
            
          </a>
          <button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
            <i class="bi bi-three-dots"></i>
          </button>
          <div class="collapse navbar-collapse" id="navpanel">
            <div id="navbar">
              <form class="search" role="search" id="search">
                <i class="bi bi-search"></i>
                <input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
              </form>
            </div>
          </div>
        </div>
      </nav>
    </header>

    <main class="container-xxl">
      <div class="toc-offcanvas">
        <div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
          <div class="offcanvas-header">
            <h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
            <button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
          </div>
          <div class="offcanvas-body">
            <nav class="toc" id="toc"></nav>
          </div>
        </div>
      </div>

      <div class="content">
        <div class="actionbar">
          <button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
            <i class="bi bi-list"></i>
          </button>

          <nav id="breadcrumb"></nav>
        </div>

        <article data-uid="">
          <h1 id="building-your-own-rendering-canvas">Building Your Own Rendering Canvas</h1>

<p>This guide provides detailed implementation information for creating your own <code>RenderingCanvas</code> using the <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a>. By understanding these implementation details, you can customize the rendering component for specific application needs or create implementations for other UI frameworks.</p>
<div class="NOTE">
<h5>Note</h5>
<p><strong>For Windows Applications</strong>: If you are developing for Windows systems, it is  recommended to directly use the existing <code>RenderingCanvas</code> implementations in the <code>Hi.WinForm</code> or <code>Hi.Wpf</code> packages, rather than creating your own. These implementations are fully tested, optimized, and maintained.</p>
<p>The implementation details provided in this document are primarily for educational purposes or for developers who need to port RenderingCanvas to other platforms/frameworks.</p>
</div>
<h2 id="basic-dispengine-usage">Basic DispEngine Usage</h2>
<p>The <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a> is designed to display objects that implement the <a class="xref" href="../../../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> interface. This is the fundamental purpose of DispEngine - to render displayable objects. Assign <a class="xref" href="../../../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> to <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_Displayee">Displayee</a>.</p>
<h2 id="core-implementation-pattern">Core Implementation Pattern</h2>
<p>When implementing a custom <code>RenderingCanvas</code> for a UI platform, follow these key steps:</p>
<ol>
<li><strong>Initialize UI Component</strong> - Set up the UI control properties and event handling</li>
<li><strong>Configure DispEngine</strong> - Create and properly initialize the <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a> instance</li>
<li><strong>Set Up Rendering Pipeline</strong> - Implement buffer swapping mechanism for visualization</li>
<li><strong>Handle User Input</strong> - Map platform-specific input events to DispEngine methods</li>
<li><strong>Manage Component Lifecycle</strong> - Ensure proper resource management and cleanup</li>
</ol>
<p>Let's examine the actual implementations in WinForm and WPF frameworks to understand these patterns in practice.</p>
<h2 id="winform-implementation-details">WinForm Implementation Details</h2>
<p>The WinForm implementation in <code>Hi.WinForm</code> combines Windows Forms controls with the <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a> rendering system.</p>
<h3 id="core-properties-and-fields">Core Properties and Fields</h3>
<p>Here are the essential properties and fields defined in the WinForm implementation:</p>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// &lt;see cref=&quot;DispEngine&quot;/&gt;.
/// &lt;/summary&gt;
public DispEngine DispEngine { get; }

// Constants and structures for WM_TOUCH
private const int WM_TOUCH = 0x0240;
private const int TOUCHEVENTF_MOVE = 0x0001;
private const int TOUCHEVENTF_DOWN = 0x0002;
private const int TOUCHEVENTF_UP = 0x0004;

[StructLayout(LayoutKind.Sequential)]
private struct TOUCHINPUT
{
    public int x;
    public int y;
    public IntPtr hSource;
    public int dwID;
    public int dwFlags;
    public int dwMask;
    public int dwTime;
    public IntPtr dwExtraInfo;
    public int cxContact;
    public int cyContact;
}

[DllImport(&quot;user32.dll&quot;)]
private static extern bool RegisterTouchWindow(IntPtr hWnd, uint ulFlags);

[DllImport(&quot;user32.dll&quot;)]
private static extern bool GetTouchInputInfo(IntPtr hTouchInput, int cInputs, [In, Out] TOUCHINPUT[] pInputs, int cbSize);

[DllImport(&quot;user32.dll&quot;)]
private static extern void CloseTouchInputHandle(IntPtr lParam);
</code></pre><h3 id="initialization">Initialization</h3>
<p>The initialization code sets up event handlers and creates the DispEngine:</p>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Ctor.
/// &lt;/summary&gt;
/// &lt;param name=&quot;displayees&quot;&gt;displayees&lt;/param&gt;
public unsafe RenderingCanvas(params IDisplayee[] displayees)
{
    // Configure the control's visual styles
    SetStyle(ControlStyles.Selectable, true);
    SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
    SetStyle(ControlStyles.ContainerControl, false);
    SetStyle(ControlStyles.ResizeRedraw, false);
    DoubleBuffered = true;

    InitializeComponent();
    Dock = DockStyle.Fill;

    // Connect event handlers for user input and window events
    this.Resize += RenderingCanvas_Resize;
    this.VisibleChanged += RenderingCanvas_VisibleChanged;
    this.MouseMove += RenderingCanvas_MouseMove;
    this.MouseDown += RenderingCanvas_MouseDown;
    this.MouseUp += RenderingCanvas_MouseUp;
    this.MouseWheel += RenderingCanvas_MouseWheel;
    this.KeyDown += RenderingCanvas_KeyDown;
    this.KeyUp += RenderingCanvas_KeyUp;

    // Add focus event handler
    this.GotFocus += RenderingCanvas_GotFocus;
    this.HandleCreated += OnHandleCreated;

    // Enable touch input and click events for the control
    this.SetStyle(ControlStyles.StandardClick, true);
    this.SetStyle(ControlStyles.StandardDoubleClick, true);
    this.TabStop = true;

    // Initialize the DispEngine with provided displayees
    DispEngine = new DispEngine(displayees);
    DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
    DispEngine.BackgroundOpacity = 0.1;
    DispEngine.SetViewToHomeView();
    DispEngine.ImageRequestAfterBufferSwapped += DispEngine_ImageRequestAfterBufferSwapped;

    // Set initial size and start the rendering engine
    this.Size = new System.Drawing.Size(500, 300);
    DispEngine.Start(this.ClientSize.Width, this.ClientSize.Height);
}
</code></pre><h3 id="rendering-pipeline">Rendering Pipeline</h3>
<p>The rendering pipeline processes images from DispEngine and displays them:</p>
<pre><code class="lang-csharp" name="RenderingCanvas">private unsafe void DispEngine_ImageRequestAfterBufferSwapped(byte* bgra_unsignedbyte_pixels, int w, int h)
{
    // Create a bitmap from the raw pixel data provided by DispEngine
    Bitmap bitmap;
    bitmap = new Bitmap(new Bitmap(w, h, w * 4,
        PixelFormat.Format32bppArgb, new IntPtr(bgra_unsignedbyte_pixels)));

    // Update the background image and dispose the previous one
    Image pre = this.BackgroundImage;
    this.BackgroundImage = bitmap;
    pre?.Dispose();
}
</code></pre><h3 id="input-handling">Input Handling</h3>
<h4 id="windows-message-handling-for-touch">Windows Message Handling for Touch</h4>
<p>WinForm implementation intercepts Windows touch messages and forwards them to DispEngine:</p>
<pre><code class="lang-csharp" name="RenderingCanvas">protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_TOUCH)
    {
        HandleTouchInput(m.WParam, m.LParam);
        return;
    }

    base.WndProc(ref m);
}

private void OnHandleCreated(object sender, EventArgs e)
{
    // Register window to receive touch messages
    RegisterTouchWindow(this.Handle, 0);
}

private void HandleTouchInput(IntPtr wParam, IntPtr lParam)
{
    int inputCount = wParam.ToInt32();
    TOUCHINPUT[] inputs = new TOUCHINPUT[inputCount];

    if (!GetTouchInputInfo(lParam, inputCount, inputs, Marshal.SizeOf(typeof(TOUCHINPUT))))
        return;

    try
    {
        for (int i = 0; i &lt; inputCount; i++)
        {
            TOUCHINPUT ti = inputs[i];
            int touchId = ti.dwID;

            // Convert touch coordinates to client coordinates
            Point touchPoint = PointToClient(new Point(ti.x / 100, ti.y / 100));

            if ((ti.dwFlags &amp; TOUCHEVENTF_DOWN) != 0)
            {
                // Touch down event
                DispEngine.TouchDown(touchId, touchPoint.X, touchPoint.Y);
                this.Focus();
            }
            else if ((ti.dwFlags &amp; TOUCHEVENTF_MOVE) != 0)
            {
                // Touch move event
                DispEngine.TouchMove(touchId, touchPoint.X, touchPoint.Y);
            }
            else if ((ti.dwFlags &amp; TOUCHEVENTF_UP) != 0)
            {
                // Touch up event
                DispEngine.TouchUp(touchId);
            }
        }
    }
    finally
    {
        CloseTouchInputHandle(lParam);
    }
}
</code></pre>
<p>The key aspect is mapping Windows touch events to DispEngine's touch API:</p>
<pre><code class="lang-csharp">// Inside HandleTouchInput method
if ((ti.dwFlags &amp; TOUCHEVENTF_DOWN) != 0)
{
    // Touch down event - delegate to DispEngine
    DispEngine.TouchDown(touchId, touchPoint.X, touchPoint.Y);
    this.Focus();
}
else if ((ti.dwFlags &amp; TOUCHEVENTF_MOVE) != 0)
{
    // Touch move event - delegate to DispEngine
    DispEngine.TouchMove(touchId, touchPoint.X, touchPoint.Y);
}
else if ((ti.dwFlags &amp; TOUCHEVENTF_UP) != 0)
{
    // Touch up event - delegate to DispEngine
    DispEngine.TouchUp(touchId);
}
</code></pre>
<h4 id="mouse-events">Mouse Events</h4>
<pre><code class="lang-csharp" name="RenderingCanvas">private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
{
    // Update mouse position and handle drag transforms
    DispEngine.MouseMove(e.Location.X, e.Location.Y);
    DispEngine.MouseDragTransform(e.Location.X, e.Location.Y,
        new mouse_button_table__transform_view_by_mouse_drag_t()
        {
            LEFT_BUTTON = (long)MouseButtons.Left,
            RIGHT_BUTTON = (long)MouseButtons.Right
        });
}

private void RenderingCanvas_MouseDown(object sender, MouseEventArgs e)
{
    // Handle mouse button press
    DispEngine.MouseButtonDown((long)e.Button);
    this.Focus();
}

private void RenderingCanvas_MouseUp(object sender, MouseEventArgs e)
{
    // Handle mouse button release
    DispEngine.MouseButtonUp((long)e.Button);
}

private void RenderingCanvas_MouseWheel(object sender, MouseEventArgs e)
{
    // Handle mouse wheel for zoom operations
    DispEngine.MouseWheel(0, e.Delta / 120);
    DispEngine.MouseWheelTransform(0, e.Delta / 120);
}
</code></pre><h4 id="keyboard-events">Keyboard Events</h4>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;inheritdoc/&gt;
protected override bool IsInputKey(Keys keyData)
{
    //since in default, arrow does not trigger key event(keyDown and keyUp).
    return true;
}

private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
{
    Focus();
    DispEngine.KeyDown((long)e.KeyData);

    // Map specific keys for view transformation
    long key = (long)e.KeyData;
    if (key == (long)Keys.LShiftKey || key == (long)Keys.RShiftKey || key == (long)Keys.ShiftKey)
        key = (long)Keys.Shift;

    DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
    {
        HOME = (long)Keys.Home,
        PAGE_UP = (long)Keys.PageUp,
        PAGE_DOWN = (long)Keys.PageDown,
        F1 = (long)Keys.F1,
        F2 = (long)Keys.F2,
        F3 = (long)Keys.F3,
        F4 = (long)Keys.F4,
        SHIFT = (long)Keys.Shift,
        ARROW_LEFT = (long)Keys.Left,
        ARROW_RIGHT = (long)Keys.Right,
        ARROW_DOWN = (long)Keys.Down,
        ARROW_UP = (long)Keys.Up
    });
}

private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
{
    DispEngine.KeyUp((long)e.KeyData);
}
</code></pre><h3 id="lifecycle-management">Lifecycle Management</h3>
<p>Window event handling ensures proper state management:</p>
<pre><code class="lang-csharp" name="RenderingCanvas">private void RenderingCanvas_Resize(object sender, EventArgs e)
{
    // Notify DispEngine of size changes
    DispEngine.Resize(this.ClientSize.Width, this.ClientSize.Height);
}

private void RenderingCanvas_VisibleChanged(object sender, EventArgs e)
{
    // Update visibility state in DispEngine
    DispEngine.IsVisible = this.Visible;
}
</code></pre><h3 id="resource-cleanup">Resource Cleanup</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt; 
/// Clean up any resources being used.
/// &lt;/summary&gt;
/// &lt;param name=&quot;disposing&quot;&gt;true if managed resources should be disposed; otherwise, false.&lt;/param&gt;
protected override void Dispose(bool disposing)
{
    if (disposing &amp;&amp; (components != null))
    {
        // Dispose the DispEngine to free resources
        DispEngine.Dispose();
        components.Dispose();
    }
    base.Dispose(disposing);
}
</code></pre><h2 id="wpf-implementation-details">WPF Implementation Details</h2>
<p>The WPF implementation uses WPF-specific controls and mechanisms but follows the same core pattern.</p>
<h3 id="core-properties">Core Properties</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// The DispEngine instance that handles rendering and user interactions
/// &lt;/summary&gt;
public DispEngine DispEngine { get; } = new DispEngine();

/// &lt;summary&gt;
/// Internal container for rendering content
/// &lt;/summary&gt;
private UserControl DisplayerPane { get; }

/// &lt;summary&gt;
/// Dictionary to store touch point information
/// &lt;/summary&gt;
private Dictionary&lt;int, Point&gt; TouchingPointsMap { get; } = new Dictionary&lt;int, Point&gt;();

/// &lt;summary&gt;
/// Dictionary to store previous positions of touch points
/// &lt;/summary&gt;
private Dictionary&lt;int, Point&gt; PreviousTouchingPointsMap { get; } = new Dictionary&lt;int, Point&gt;();
</code></pre><h3 id="initialization-1">Initialization</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Initializes a new instance of the RenderingCanvas
/// &lt;/summary&gt;
public RenderingCanvas()
{
    DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
    DispEngine.BackgroundOpacity = 0.1;

    // Configure the main control properties
    HorizontalAlignment = HorizontalAlignment.Stretch;
    VerticalAlignment = VerticalAlignment.Stretch;
    Focusable = true;
    KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
    DataContextChanged += CanvasDataContextChanged;

    // Create and configure the display pane
    DisplayerPane = new UserControl();
    DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
    DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
    DisplayerPane.Focusable = true;
    DisplayerPane.IsTabStop = true;

    // Connect event handlers for user input and window events
    DisplayerPane.SizeChanged += RenderingCanvas_SizeChanged;
    DisplayerPane.MouseMove += RenderingCanvas_MouseMove;
    DisplayerPane.MouseDown += RenderingCanvas_MouseDown;
    DisplayerPane.MouseUp += RenderingCanvas_MouseUp;
    DisplayerPane.MouseWheel += RenderingCanvas_MouseWheel;
    DisplayerPane.KeyDown += RenderingCanvas_KeyDown;
    DisplayerPane.KeyUp += RenderingCanvas_KeyUp;
    DisplayerPane.Loaded += RenderingCanvas_Loaded;
    DisplayerPane.Unloaded += RenderingCanvas_Unloaded;
    DisplayerPane.IsVisibleChanged += DisplayerPane_IsVisibleChanged;

    // Add touch event handlers
    DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
    DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
    DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
    
    // Enable touch support
    this.IsManipulationEnabled = true;

    // Initialize power management
    InitializePowerManagement();

    // Add the display pane to this control's content
    Content = DisplayerPane;
}
</code></pre><h3 id="rendering-pipeline-1">Rendering Pipeline</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Handles the buffer swapped event from DispEngine
/// &lt;/summary&gt;
private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
{
    if (data == null)
        return;

    Span&lt;byte&gt; bgra = new Span&lt;byte&gt;(data, w * h * 4);

    // Copy pixel data from DispEngine
    int n = w * h * 4;
    byte[] arr = new byte[n];
    for (int i = 0; i &lt; n; i++)
        arr[i] = data[i];
    
    // Update UI on the UI thread
    DisplayerPane.Dispatcher.InvokeAsync(() =&gt;
    {
        BitmapSource bitmap = BitmapSource.Create(w, h, 1, 1, PixelFormats.Bgra32, null, arr, w * 4);
        DisplayerPane.Background = new ImageBrush(bitmap);
    });
}

/// &lt;summary&gt;
/// Handles the size changed event
/// &lt;/summary&gt;
private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
    // Notify DispEngine of size changes
    DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
}

/// &lt;summary&gt;
/// Handles visibility changes
/// &lt;/summary&gt;
private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    // Update visibility state in DispEngine
    DispEngine.IsVisible = IsVisible;
}
</code></pre><h3 id="mouse-and-keyboard-handling">Mouse and Keyboard Handling</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Helper method to get mouse button mask
/// &lt;/summary&gt;
internal static HiMouseButtonMask GetMouseButtonMask(MouseDevice device)
{
    HiMouseButtonMask mouseButtonMask = 0;
    mouseButtonMask.SetLeftPressed(device.LeftButton == MouseButtonState.Pressed);
    mouseButtonMask.SetMiddlePressed(device.MiddleButton == MouseButtonState.Pressed);
    mouseButtonMask.SetRightPressed(device.RightButton == MouseButtonState.Pressed);
    mouseButtonMask.SetXButton1Pressed(device.XButton1 == MouseButtonState.Pressed);
    mouseButtonMask.SetXButton2Pressed(device.XButton2 == MouseButtonState.Pressed);
    return mouseButtonMask;
}

/// &lt;summary&gt;
/// Handles the mouse wheel event
/// &lt;/summary&gt;
private void RenderingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
    // Handle mouse wheel for zoom operations
    DispEngine.MouseWheel(0, e.Delta / 120);
    DispEngine.MouseWheelTransform(0, e.Delta / 120);
}

/// &lt;summary&gt;
/// Handles the mouse up event
/// &lt;/summary&gt;
private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
    // Handle mouse button release
    DispEngine.MouseButtonUp((long)e.ChangedButton);
    (sender as UIElement)?.ReleaseMouseCapture();
}

/// &lt;summary&gt;
/// Handles the mouse down event
/// &lt;/summary&gt;
private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
    // Handle mouse button press
    DispEngine.MouseButtonDown((long)e.ChangedButton);
    DisplayerPane.Focus();
    (sender as UIElement)?.CaptureMouse();
}

/// &lt;summary&gt;
/// Handles the mouse move event
/// &lt;/summary&gt;
private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
{
    // Update mouse position and handle drag transforms
    Point p = e.GetPosition(DisplayerPane);
    DispEngine.MouseMove((int)p.X, (int)p.Y);
    DispEngine.MouseDragTransform((int)p.X, (int)p.Y,
        new mouse_button_table__transform_view_by_mouse_drag_t()
        {
            LEFT_BUTTON = (long)MouseButton.Left,
            RIGHT_BUTTON = (long)MouseButton.Right
        });
}
</code></pre><pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Handles the key up event
/// &lt;/summary&gt;
private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
{
    DispEngine.KeyUp((long)e.Key);
}

/// &lt;summary&gt;
/// Handles the key down event
/// &lt;/summary&gt;
private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
{
    DispEngine.KeyDown((long)e.Key);

    // Map specific keys for view transformation
    long key = (long)e.Key;
    if (key == (long)Key.RightShift)
        key = (long)Key.LeftShift;
        
    DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
    {
        HOME = (long)Key.Home,
        PAGE_UP = (long)Key.PageUp,
        PAGE_DOWN = (long)Key.PageDown,
        F1 = (long)Key.F1,
        F2 = (long)Key.F2,
        F3 = (long)Key.F3,
        F4 = (long)Key.F4,
        SHIFT = (long)Key.LeftShift,
        ARROW_LEFT = (long)Key.Left,
        ARROW_RIGHT = (long)Key.Right,
        ARROW_DOWN = (long)Key.Down,
        ARROW_UP = (long)Key.Up
    });
}
</code></pre><h3 id="lifecycle-management-1">Lifecycle Management</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Handles window state changes (maximize, minimize, etc.)
/// &lt;/summary&gt;
private unsafe void RenderingCanvas_StateChanged(object sender, EventArgs e)
{
    switch ((sender as Window).WindowState)
    {
        case WindowState.Maximized:
            DispEngine.IsVisible = true;
            break;
        case WindowState.Minimized:
            DispEngine.IsVisible = false;
            break;
        case WindowState.Normal:
            DispEngine.IsVisible = true;
            break;
    }
}

/// &lt;summary&gt;
/// Handles data context changes
/// &lt;/summary&gt;
private unsafe void CanvasDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    DispEngine pre = e.OldValue as DispEngine;
    DispEngine cur = e.NewValue as DispEngine;

    //child's binding event is triggered after IsVisible event and Load event.
    if (pre != null)    //this section will never occur if the datacontext not set twice.
    {
        pre.Terminate();
        pre.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
    }
    if (cur != null)
    {
        cur.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
        cur.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);

        cur.IsVisible = IsVisible;
    }
}

/// &lt;summary&gt;
/// Reference to the current window containing this control
/// &lt;/summary&gt;
private Window currentWindow;

/// &lt;summary&gt;
/// Gets or sets the current window, connecting or disconnecting state change events
/// &lt;/summary&gt;
Window CurrentWindow
{
    get =&gt; currentWindow; set
    {
        if (currentWindow != null)
            currentWindow.StateChanged -= RenderingCanvas_StateChanged;
        currentWindow = value;
        if (currentWindow != null)
            currentWindow.StateChanged += RenderingCanvas_StateChanged;
    }
}

/// &lt;summary&gt;
/// Handles the loaded event
/// &lt;/summary&gt;
private unsafe void RenderingCanvas_Loaded(object sender, RoutedEventArgs e)
{
    // Get the window containing this control
    CurrentWindow = Window.GetWindow(this);
    
    // Set up DispEngine rendering
    DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
    DispEngine.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
    DispEngine.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
    DispEngine.IsVisible = IsVisible;
}

/// &lt;summary&gt;
/// Handles the unloaded event
/// &lt;/summary&gt;
private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
{
    DispEngine.IsVisible = IsVisible;
    DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
    CurrentWindow = null;
}
</code></pre><h3 id="resource-cleanup-1">Resource Cleanup</h3>
<pre><code class="lang-csharp" name="RenderingCanvas">/// &lt;summary&gt;
/// Flag to track disposed state
/// &lt;/summary&gt;
private bool disposedValue;

/// &lt;summary&gt;
/// Disposes managed resources
/// &lt;/summary&gt;
protected virtual void Dispose(bool disposing)
{
    if (!disposedValue)
    {
        if (disposing)
        {
            // Unsubscribe from power events
            SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
            
            // Dispose the DispEngine to free resources
            DispEngine.Dispose();
        }
        disposedValue = true;
    }
}

/// &lt;summary&gt;
/// Public dispose method to free resources
/// &lt;/summary&gt;
public void Dispose()
{
    // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
    Dispose(disposing: true);
    GC.SuppressFinalize(this);
}
</code></pre><h2 id="core-dispengine-integration-patterns">Core DispEngine Integration Patterns</h2>
<h3 id="1-initialization-sequence">1. Initialization Sequence</h3>
<pre><code class="lang-csharp">// Create DispEngine (optionally with displayees)
var engine = new DispEngine(displayees);

// Set up image buffer callback
engine.ImageRequestAfterBufferSwapped += OnBufferSwapped;

// Initialize with canvas size
engine.Start(width, height);

// Set initial view (optional)
engine.SetViewToHomeView();
</code></pre>
<h3 id="2-render-loop">2. Render Loop</h3>
<p>The rendering process follows this pattern:</p>
<ol>
<li><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a> processes <a class="xref" href="../../../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> objects</li>
<li>Buffer is swapped and callback is triggered</li>
<li>UI framework renders the buffer to screen</li>
<li>User input triggers view updates</li>
<li>Process repeats</li>
</ol>
<h3 id="3-complete-user-input-mapping">3. Complete User Input Mapping</h3>
<p>All user interactions must be mapped to <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a> methods:</p>
<table>
<thead>
<tr>
<th>User Action</th>
<th>DispEngine Method</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mouse move</td>
<td><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseMove_System_Int32_System_Int32_">MouseMove(int, int)</a></td>
</tr>
<tr>
<td>Mouse drag</td>
<td><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseDragTransform_System_Int32_System_Int32_Hi_Native_mouse_button_table__transform_view_by_mouse_drag_t_">MouseDragTransform(int, int, mouse_button_table__transform_view_by_mouse_drag_t)</a></td>
</tr>
<tr>
<td>Mouse button</td>
<td><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseButtonDown_System_Int64_">MouseButtonDown(long)</a> / <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseButtonUp_System_Int64_">MouseButtonUp(long)</a></td>
</tr>
<tr>
<td>Mouse wheel</td>
<td><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseWheel_System_Int32_System_Int32_">MouseWheel(int, int)</a> and <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseWheelTransform_System_Int32_System_Int32_System_Double_">MouseWheelTransform(int, int, double)</a></td>
</tr>
<tr>
<td>Key press</td>
<td><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_KeyDown_System_Int64_">KeyDown(long)</a> / <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_KeyUp_System_Int64_">KeyUp(long)</a> and <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_KeyDownTransform_System_Int64_Hi_Native_key_table__transform_view_by_key_pressing_t_">KeyDownTransform(long, key_table__transform_view_by_key_pressing_t)</a></td>
</tr>
<tr>
<td>Touch events</td>
<td><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TouchDown_System_Int32_System_Int32_System_Int32_">TouchDown(int, int, int)</a> / <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TouchMove_System_Int32_System_Int32_System_Int32_">TouchMove(int, int, int)</a> / <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TouchUp_System_Int32_">TouchUp(int)</a></td>
</tr>
</tbody>
</table>
<h3 id="4-proper-resource-cleanup">4. Proper Resource Cleanup</h3>
<p>Resource management is critical for proper operation:</p>
<pre><code class="lang-csharp">// In dispose method
DispEngine.ImageRequestAfterBufferSwapped -= OnBufferSwapped;
DispEngine.Terminate();
DispEngine.Dispose();
</code></pre>
<h2 id="advanced-implementation-considerations">Advanced Implementation Considerations</h2>
<p>When creating custom implementations, consider these aspects:</p>
<h3 id="view-manipulation">View Manipulation</h3>
<p>Use <a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_SketchView">SketchView</a> to directly access or modify the view matrix:</p>
<pre><code class="lang-csharp">// Get current view matrix
Mat4d currentView = engine.SketchView;

// Apply custom rotation
Mat4d rotation = Mat4d.RotateX(Math.PI/4);
engine.SketchView = currentView * rotation;
</code></pre>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../../../../../api/Hi.Disp.DispEngine.html">DispEngine</a></li>
<li><a class="xref" href="../../../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a></li>
<li><a class="xref" href="../../../../../api/Hi.Geom.Vec2d.html">Vec2d</a></li>
<li><a class="xref" href="../../../../../api/Hi.Geom.Mat4d.html">Mat4d</a></li>
</ul>

</article>

        <div class="contribution d-print-none">
        </div>

        <div class="next-article d-print-none border-top" id="nextArticle"></div>

      </div>

      <div class="affix">
        <nav id="affix"></nav>
      </div>
    </main>

    <div class="container-xxl search-results" id="search-results"></div>

    <footer class="border-top text-secondary">
      <div class="container-xxl">
        <div class="flex-fill">
          <span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
        </div>
      </div>
    </footer>
  </body>
</html>
